plotly¶
This provides an overview to using plotly as the plotting engine with fivecentplots
Setup¶
Import packages
%load_ext autoreload
%autoreload 2
import fivecentplots as fcp
import pandas as pd
import imageio.v3 as imageio
import cv2
from pathlib import Path
fcp.__version__
The autoreload extension is already loaded. To reload it, use:
%reload_ext autoreload
'0.6.0-a2'
Sample data¶
Several data sets are used in this tutorial:
x-y data¶
df_xy = pd.read_csv(Path(fcp.__file__).parent / 'test_data/fake_data.csv')
df_xy.head(10)
| Substrate | Target Wavelength | Boost Level | Temperature [C] | Die | Voltage | I Set | I [A] | |
|---|---|---|---|---|---|---|---|---|
| 0 | Si | 450 | 0.2 | 25 | (1,1) | 0.0 | 0.0 | 0.0 |
| 1 | Si | 450 | 0.2 | 25 | (1,1) | 0.1 | 0.0 | 0.0 |
| 2 | Si | 450 | 0.2 | 25 | (1,1) | 0.2 | 0.0 | 0.0 |
| 3 | Si | 450 | 0.2 | 25 | (1,1) | 0.3 | 0.0 | 0.0 |
| 4 | Si | 450 | 0.2 | 25 | (1,1) | 0.4 | 0.0 | 0.0 |
| 5 | Si | 450 | 0.2 | 25 | (1,1) | 0.5 | 0.0 | 0.0 |
| 6 | Si | 450 | 0.2 | 25 | (1,1) | 0.6 | 0.0 | 0.0 |
| 7 | Si | 450 | 0.2 | 25 | (1,1) | 0.7 | 0.0 | 0.0 |
| 8 | Si | 450 | 0.2 | 25 | (1,1) | 0.8 | 0.0 | 0.0 |
| 9 | Si | 450 | 0.2 | 25 | (1,1) | 0.9 | 0.0 | 0.0 |
Time series data¶
ts = pd.read_csv(Path(fcp.__file__).parent / 'test_data/fake_ts.csv')
ts.head()
| Date | Happiness Quotient | |
|---|---|---|
| 0 | 1/1/2015 | 16.088954 |
| 1 | 1/2/2015 | 18.186724 |
| 2 | 1/3/2015 | 35.744313 |
| 3 | 1/4/2015 | 38.134045 |
| 4 | 1/5/2015 | 46.147279 |
Bar plot data¶
df_bar = pd.read_csv(Path(fcp.__file__).parent / 'test_data/fake_data_bar.csv')
df_bar.head()
| Liquid | pH | Measurement | T [C] | |
|---|---|---|---|---|
| 0 | Lemon juice | 2.4 | A | 25 |
| 1 | Orange juice | 3.5 | A | 25 |
| 2 | Battery acid | 1.0 | A | 25 |
| 3 | Bottled water | 6.7 | A | 25 |
| 4 | Coke | 3.0 | A | 25 |
Box plot data¶
df_box = pd.read_csv(Path(fcp.__file__).parent / 'test_data/fake_data_box.csv')
df_box.head()
| Batch | Sample | Region | Value | ID | |
|---|---|---|---|---|---|
| 0 | 101 | 1 | Alpha123 | 3.5 | ID701223A |
| 1 | 101 | 1 | Alpha123 | 0.0 | ID7700-1222B |
| 2 | 101 | 1 | Alpha123 | 3.3 | ID701223A |
| 3 | 101 | 1 | Alpha123 | 3.2 | ID7700-1222B |
| 4 | 101 | 1 | Alpha123 | 4.0 | ID701223A |
Contour data¶
df_contour = pd.read_csv(Path(fcp.__file__).parent / 'test_data/fake_data_contour.csv')
df_contour.head()
| Experiment | Batch | X | Y | Value | |
|---|---|---|---|---|---|
| 0 | Control | 101 | 1 | -4 | 3.5 |
| 1 | Control | 101 | 1 | -2 | 2.1 |
| 2 | Control | 101 | 1 | 0 | 3.3 |
| 3 | Control | 101 | 1 | 2 | 3.2 |
| 4 | Control | 101 | 1 | 4 | 4.0 |
Gantt data¶
df_gantt = pd.read_csv(Path(fcp.__file__).parent / 'test_data/fake_data_gantt.csv')
df_gantt.head()
| Task | Assigned | Start | Stop | Category | |
|---|---|---|---|---|---|
| 0 | Record drums | Taylor | 2010-09-01 | 2010-09-05 | Recording |
| 1 | Record bass | Nate | 2010-09-04 | 2010-09-06 | Recording |
| 2 | Record rhythm guitar | Pat | 2010-09-06 | 2010-09-08 | Recording |
| 3 | Record rhythm guitar | Dave | 2010-09-06 | 2010-09-08 | Recording |
| 4 | Record lead guitar | Chris | 2010-09-07 | 2010-09-09 | Recording |
Heatmap data¶
df_heatmap = pd.read_csv(Path(fcp.__file__).parent / 'test_data/fake_data_heatmap.csv')
df_heatmap.head()
| Player | Category | Average | |
|---|---|---|---|
| 0 | Lebron James | Points | 27.5 |
| 1 | Lebron James | Assists | 9.1 |
| 2 | Lebron James | Rebounds | 8.6 |
| 3 | Lebron James | Blocks | 0.9 |
| 4 | James Harden | Points | 30.4 |
Histogram data¶
df_hist = pd.read_csv(Path(fcp.__file__).parent / 'test_data/fake_data_box.csv')
img_hist = cv2.imread(str(Path(fcp.__file__).parent / 'test_data/imshow_cat_pirate.png'))
Image data¶
img_bgr = cv2.imread(str(Path(fcp.__file__).parent / 'test_data/imshow_cat_pirate.png'))
img_rgb = cv2.cvtColor(img_bgr, cv2.COLOR_BGR2RGB)
Theme and shortcuts¶
Load a custom theme file for plotly:
fcp.set_theme('gray_plotly')
Previous theme file found! Renaming to "defaults_old.py" and copying theme "gray_plotly"...done!
Note
While many theme parameters can be common between matplotlib and plotly, certain differences between the engines (such as the default dpi) make it easier to use a custom theme file for each engine
Define some scope-wide shortcuts to avoid having to enter certain kwargs into each function call (i.e., these are automatically added):
fcp.KWARGS['inline'] = True
fcp.KWARGS['engine'] = 'plotly'
Caution¶
Not all features available in matplotlib are available in plotly. fivecentplots will attempt to warn you if you are requesting an unsupported feature, but not every possible option has been tested. Buyer beware (and then file a bug report!)
plot¶
Scatter¶
Filtered¶
fcp.plot(df_xy, x='Voltage', y='I [A]', title='IV Data', lines=False,
filter='Substrate=="Si" & Target Wavelength==450 & Boost Level==0.2 & Temperature [C]==25')
Legend¶
fcp.plot(df_xy, x='Voltage', y='I [A]', legend='Die',
filter='Substrate=="Si" & Target Wavelength==450 & Boost Level==0.2 & Temperature [C]==25')
Log axis¶
Note
symlog and logit not yet supported
fcp.plot(df_xy, x='Voltage', y='I [A]', ax_scale='loglog', legend='Die', xmin=0.9, xmax=2.1, grid_minor=True,
filter='Substrate=="Si" & Target Wavelength==450 & Boost Level==0.2 & Temperature [C]==25')
Categorical tick labels¶
fcp.plot(df_xy, x='Die', y='I [A]',
filter='Substrate=="Si" & Target Wavelength==450 & Boost Level==0.2 & Temperature [C]==25 & Voltage==1.5')
Secondary axes¶
Note
Not all secondary and multiple axes cases are shown below but all the matplotlib examples in plot have been ported
fcp.plot(df_xy, x='Voltage', y=['Voltage', 'I [A]'], twin_x=True, legend='Die',
grid_major_y2=True, grid_major_y2_style='--', y2max=1.4,
filter='Substrate=="Si" & Target Wavelength==450 & Boost Level==0.2 & Temperature [C]==25 & Die=="(-1,2)"')
Multiple x & y values¶
fcp.plot(df_xy, x=['Boost Level', 'I [A]'], y=['Voltage', 'Temperature [C]'], legend='Die',
filter='Substrate=="Si" & Target Wavelength==450 & Boost Level==0.2 & Temperature [C]==25')
Grouping¶
Row plot¶
fcp.plot(df_xy, x='Voltage', y='I [A]', legend='Die', row='Boost Level', ax_size=[225, 225], legend_edge_color='#000000',
filter='Substrate=="Si" & Target Wavelength==450 & Temperature [C]==25', label_row_fill_color='#000000', ax_edge_width=4,
label_row_font_color='#ff0000', label_row_edge_color='#0000ff', label_row_edge_width=2, legend_edge_width=3)
Warning: The following kwargs are not supported:
- label_row_font_color
Column plot¶
fcp.plot(df_xy, x='Voltage', y='I [A]', legend='Die', col='Boost Level', ax_size=[225, 225], legend_edge_color='#000000', ax_edge_width=5,
filter='Substrate=="Si" & Target Wavelength==450 & Temperature [C]==25', label_col_fill_color='#000000', label_col_font_color='#ff0000')
Warning: The following kwargs are not supported:
- label_col_font_color
Row x column grid¶
fcp.plot(df_xy, x='Voltage', y='I [A]', legend='Die', col='Boost Level', row='Temperature [C]',
modebar_visible=True, modebar_fill_color='#000000', ax_edge_width=1, ymin=0,
ax_size=[225, 225], filter='Substrate=="Si" & Target Wavelength==450', label_rc_font_size=13)
Wrap plot¶
fcp.plot(df_xy, x='Voltage', y='I [A]', legend='Die', wrap=['Temperature [C]', 'Boost Level'],
ax_size=[225, 225], filter='Substrate=="Si" & Target Wavelength==450', label_rc_font_size=13)
Horizontal & vertical lines¶
fcp.plot(df_xy, x='Voltage', y='I [A]', title='IV Data', lines=False, legend=True,
filter='Substrate=="Si" & Target Wavelength==450 & Boost Level==0.2 & Temperature [C]==25',
ax_hlines=[(0, '#FF0000', '--', 3, 1, 'Open', '#555555', 0.25), 1.2],
ax_vlines=[(0.6, '#0000ff', ':'), (1, '#00FF00')])
Curve fitting¶
fcp.plot(df_xy, x='Voltage', y='I [A]', title='IV Data', lines=False,
filter='Substrate=="Si" & Target Wavelength==450 & Boost Level==0.2 & Temperature [C]==25',
fit=1, fit_eqn=True, fit_rsq=True, fit_range_x=[1.3, 2])
Stat Lines¶
fcp.plot(df_xy, x='Voltage', y=['Boost Level', 'I [A]'], legend=True, stat='median',
filter='Substrate=="Si" & Target Wavelength==450 & Boost Level==0.2 & Temperature [C]==25')
Confidence intervals¶
To demonstrate this feature we will use a special dataset:
df_interval = pd.read_csv(Path(fcp.__file__).parent / 'test_data/fake_data_interval.csv')
df_interval.head()
| x | y | |
|---|---|---|
| 0 | -1.0 | -10.715459 |
| 1 | -1.0 | -9.972410 |
| 2 | -1.0 | -30.740532 |
| 3 | -1.0 | -31.368963 |
| 4 | -1.0 | -29.058633 |
fcp.plot(df_interval, x='x', y='y', lines=False, conf_int=0.95)
Control limits¶
fcp.plot(df_interval, x='x', y='y', lines=False, ucl=50, lcl=-50, ucl_fill_color='#FF0000', legend=True)
Reference line¶
fcp.plot(df_xy, x='Voltage', y='I [A]', title='IV Data', legend='Die',
filter='Substrate=="Si" & Target Wavelength==450 & Boost Level==0.2 & Temperature [C]==25',
ref_line=df_xy['Voltage'], ref_line_legend_text='y=x', xmin=0, ymin=0, xmax=1.6, ymax=1.6)
bar¶
fcp.bar(df_bar, x='Liquid', y='pH', filter='Measurement=="A" & T [C]==25', horizontal=True)
fcp.bar(df_bar, x='Liquid', y='pH', tick_labels_major_x_rotation=90, legend='Measurement')
fcp.bar(df_bar, x='Liquid', y='pH', tick_labels_major_x_rotation=90, stacked=True, legend='Measurement')
fcp.bar(df_bar, x='Liquid', y='pH', tick_labels_major_x_rotation=90, col='Measurement', row='T [C]', ax_hlines=0, ax_size=[300, 300])
boxplot¶
fcp.boxplot(df_box, y='Value', groups=['Batch', 'Sample'], group_means=True)
df_box['Row'] = [int(f) for f in df_box.index / 4]
fcp.boxplot(df_box, y='Value', groups=['Batch', 'Sample'], mean_diamonds=True, conf_coeff=0.95, legend='Row')
fcp.boxplot(df_box, y='Value', groups=['Batch', 'Sample'], violin=True)
fcp.boxplot(df_box, y='Value', groups=['Batch', 'Sample'], col='Region', ax_size=[300, 300])
contour¶
fcp.contour(df_contour, x='X', y='Y', z='Value', filled=False, cbar=False)
fcp.contour(df_contour, x='X', y='Y', z='Value', filled=False, levels=40, contour_width=2,
xmin=-4, xmax=5, ymin=-4, ymax=6, cbar=True,
show_points=True, marker_size=26, marker_fill_color='#00FF00')
Warning: The following kwargs are not supported:
- contour_width
fcp.contour(df_contour, x='X', y='Y', z='Value', row='Batch', col='Experiment', filled=True,
cbar=False, xmin=-3, xmax=3, ymin=-3, ymax=3, ax_size=[250,250],
label_rc_font_size=12, levels=40)
gantt¶
Better luck next time…
hist¶
fcp.hist(df_hist, x='Value', horizontal=True, bins=20)
fcp.hist(df_hist, x='Value', legend='Region', kde=True, kde_width=2)
Warning: The following kwargs are not supported:
- kde_width
---------------------------------------------------------------------------
AttributeError Traceback (most recent call last)
Cell In[48], line 1
----> 1 fcp.hist(df_hist, x='Value', legend='Region', kde=True, kde_width=2)
File ~/Code/fivecentplots/src/fivecentplots/fcp.py:502, in hist(df, **kwargs)
409 def hist(df, **kwargs):
410 """Histogram plot.
411
412 Args:
(...)
499 .. figure:: ../_static/images/example_hist2.png
500 """
--> 502 return plotter(data.Histogram, **utl.dfkwarg(df, kwargs, data.Histogram))
File ~/Code/fivecentplots/src/fivecentplots/fcp.py:1686, in plotter(dobj, **kwargs)
1683 kwargs['timer'].get(f'ifig={ifig} | ir={ir} | ic={ic} | add_hvlines')
1685 # Plot the data
-> 1686 dd = globals()['plot_{}'.format(dd.name)](dd, layout, ir, ic, df_rc, kwargs)
1687 kwargs['timer'].get(f'ifig={ifig} | ir={ir} | ic={ic} | plot')
1689 # Add rc labels
File ~/Code/fivecentplots/src/fivecentplots/fcp.py:1416, in plot_hist(data, layout, ir, ic, df_rc, kwargs)
1399 """
1400 Plot data as histogram
1401
(...)
1409
1410 """
1411 for iline, df, x, y, z, leg_name, twin, ngroups in data.get_plot_data(df_rc):
1412 # if kwargs.get('groups', False): # no use case for this
1413 # for nn, gg in df.groupby(utl.validate_list(kwargs['groups'])):
1414 # hist, data = layout.plot_hist(ir, ic, iline, gg, x, y, leg_name, data)
1415 # else:
-> 1416 hist, data = layout.plot_hist(ir, ic, iline, df, x, y, leg_name, data)
1418 return data
File ~/Code/fivecentplots/src/fivecentplots/engines/plotly.py:1602, in Layout.plot_hist(self, ir, ic, iline, df, x, y, leg_name, data)
1600 y0 = np.linspace(data.ranges['ymin'][ir, ic], data.ranges['ymax'][ir, ic], 1000)
1601 x0 = kde(y0)
-> 1602 kwargs = self.make_kw_dict(self.kde)
1603 kwargs['color'] = RepeatedList(kwargs['color'][iline], 'color')
1604 mls = dict(line=dict(width=self.kde.width[iline],
1605 color=self.kde.color[iline],
1606 dash=self.kde.style[iline],
1607 ))
File ~/Code/fivecentplots/src/fivecentplots/engines/layout.py:2776, in BaseLayout.make_kw_dict(self, element, pop)
2774 kwargs['edge_color'] = copy.copy(element.edge_color)
2775 kwargs['edge_width'] = copy.copy(element.edge_width)
-> 2776 kwargs['edge_width_adj'] = copy.copy(element.edge_width_adj)
2777 kwargs['font'] = copy.copy(element.font)
2778 kwargs['font_weight'] = copy.copy(element.font_weight)
AttributeError: 'Element' object has no attribute 'edge_width_adj'
[ ]:
fcp.hist(img_rgb, legend='Channel', markers=False, ax_size=[600, 400], line_width=2, colors=fcp.RGB)
> /Users/steve/Code/fivecentplots/src/fivecentplots/engines/plotly.py(2033)show()
2031 # pio.renderers.default = 'iframe' # not sure about this
2032 db()
-> 2033 self.fig.obj.show(config=config)
2034
2035 def update_markers(self):
imshow¶
fcp.imshow(img_rgb, ax_size=[600, 300])
img_raw = fcp.utilities.img_grayscale(img_rgb)
fcp.imshow(img_raw, ax_size=[600, 600], title='Fake RAW, Fake Pirate', cbar=True, title_edge_width=1, title_edge_color='#ff0000')
url = 'https://upload.wikimedia.org/wikipedia/commons/2/28/RGB_illumination.jpg'
img_rgb_sp = imageio.imread(url)
img_raw_sp = fcp.utilities.rgb2bayer(img_rgb_sp)
fcp.imshow(img_raw_sp, cmap='inferno', ax_size=[300, 300], cfa='rggb', wrap='Plane', ax_edge_width=1, ax_edge_color='#555555')
nq¶
fcp.nq(df_box, x='Value', marker_size=4, line_width=2)
img_rgb = cv2.imread(str(Path(fcp.__file__).parent / 'test_data/imshow_cat_pirate.png'))
img_cat = fcp.utl.img_grayscale(img_rgb, bit_depth=12)
fcp.nq(img_cat, marker_size=4, line_width=2)
pie¶
df_pie = df_bar.copy()
df_pie.loc[df_pie.pH < 0, 'pH'] = -df_pie.pH
fcp.pie(df_pie, x='Liquid', y='pH', filter='Measurement=="A" & T [C]==25')
fcp.pie(df_pie, x='Liquid', y='pH', filter='Measurement=="A" & T [C]==25', explode=[0.1], legend=True)
> /Users/steve/Code/fivecentplots/src/fivecentplots/engines/plotly.py(2458)show()
2456 # pio.renderers.default = 'iframe' # not sure about this
2457 db()
-> 2458 self.fig.obj.show(config=config)
2459
2460 def update_markers(self):